package com.yunquan.ohana.base.ui

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProviders
import com.trello.rxlifecycle4.components.support.RxFragment
import com.yunquan.ohana.base.ui.inter.IBaseView
import com.yunquan.ohana.dialog.LoadingDialog
import java.lang.reflect.ParameterizedType

abstract class BaseFragment<V : ViewDataBinding, VM : BaseViewModel> : RxFragment(),
    IBaseView {
    var binding: V? = null
    var viewModel: VM? = null
    private var viewModelId: Int? = null

    private val mActivityResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        onActivityResult(result)
    }

    open fun onActivityResult(result: ActivityResult) {

    }

    override fun initParam() {}

    override fun initViewObservable() {

    }

    abstract fun initContentView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): Int

    abstract fun initVariableId(): Int

    open fun initViewModel(): VM? {
        return null
    }

    fun refreshLayout() {
        if (viewModel != null) {
            binding?.setVariable(viewModelId!!, viewModel)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initParam()
    }

    override fun onDestroy() {
        super.onDestroy()
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val layoutId = initContentView(inflater, container, savedInstanceState)
        binding = DataBindingUtil.inflate(inflater, layoutId, container, false)
        return binding!!.root
    }

    override fun onDestroyView() {
        binding?.unbind()
        // 释放对视图的强引用，避免在视图销毁后仍持有导致内存泄漏
        binding = null
        viewModel?.removeRxBus()
        super.onDestroyView()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //私有的初始化Databinding和ViewModel方法
        initViewDataBinding()
        //私有的ViewModel与View的契约事件回调逻辑
        registerUIChangeLiveDataCallBack()
        //页面数据初始化方法
        initData(savedInstanceState)
        //页面事件监听的方法，一般用于ViewModel层转到View层的事件注册
        initViewObservable()
        //注册RxBus
        viewModel?.registerRxBus()
    }

    private fun initViewDataBinding() {
        viewModelId = initVariableId()
        viewModel = initViewModel()
        if (viewModel == null) {
            val type = javaClass.genericSuperclass
            val modelClass: Class<out ViewModel> = if (type is ParameterizedType) {
                type.actualTypeArguments[1] as Class<out ViewModel>
            } else {
                //如果没有指定泛型参数，则默认使用BaseViewModel
                BaseViewModel::class.java
            }
            viewModel = createViewModel(this, modelClass) as VM
        }
        binding?.setVariable(viewModelId!!, viewModel)
        // 支持LiveData绑定xml，数据改变，UI自动会更新。
        // 使用 Fragment 的 viewLifecycleOwner，避免在 Fragment 的视图销毁后仍持有引用导致内存泄漏。
        binding?.setLifecycleOwner(viewLifecycleOwner)
        //让ViewModel拥有View的生命周期感应
        lifecycle.addObserver(viewModel!!)
        //注入RxLifecycle生命周期
        viewModel?.injectLifecycleProvider(this)
    }

    private fun registerUIChangeLiveDataCallBack() {

        //加载对话框显示
        viewModel?.getUIChangeLiveData()?.showDialogEvent?.observe(viewLifecycleOwner) { value ->
            showLoading(value!!)
        }

        //加载对话框消失
        viewModel?.getUIChangeLiveData()?.dismissDialogEvent?.observe(viewLifecycleOwner) {
            dismissLoading()
        }

        //跳入新页面
        viewModel?.getUIChangeLiveData()?.startActivityEvent?.observe(viewLifecycleOwner) { params ->
            val clz = params!![ParameterField.CLASS] as Class<*>
            val bundle = params[ParameterField.BUNDLE] as Bundle?
            startActivity(clz, bundle)
        }

        //跳入新页面 带返回值
        viewModel?.getUIChangeLiveData()?.startActivityForResultEvent?.observe(viewLifecycleOwner) { params ->
            val clz = params!![ParameterField.CLASS] as Class<*>
            val bundle = params[ParameterField.BUNDLE] as Bundle?
            startActivityForResult(clz, bundle)
        }

        //关闭界面
        viewModel?.getUIChangeLiveData()?.finishEvent?.observe(viewLifecycleOwner) {
            requireActivity().finish()
        }

        //关闭上一层
        viewModel?.getUIChangeLiveData()?.onBackPressedEvent?.observe(viewLifecycleOwner) {
            requireActivity().onBackPressedDispatcher.onBackPressed()
        }
    }

    fun showLoading(text: String? = null) {
        if (LoadingDialog.getInstance().isShowing()) {
            return
        }
        LoadingDialog.getInstance().show(text)
    }

    fun dismissLoading() {
        LoadingDialog.getInstance().dismiss()
    }

    fun startActivity(clz: Class<*>) {
        startActivity(clz, null)
    }

    fun startActivity(clz: Class<*>, bundle: Bundle?) {
        val intent = Intent(context, clz)
        bundle?.let { intent.putExtras(it) }
        startActivity(intent)
    }

    fun startActivityForResult(clz: Class<*>, bundle: Bundle?) {
        val intent = Intent(context, clz)
        bundle?.let {
            intent.putExtras(it)
        }
        mActivityResult.launch(intent)
    }

    fun isBackPressed(): Boolean {
        return false
    }

    private fun <T : ViewModel> createViewModel(fragment: Fragment, cls: Class<T>): T {
        return ViewModelProviders.of(fragment)[cls]
    }
}